package com.swift.authority.common.util;

import com.alibaba.fastjson.JSON;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.swift.authority.common.constant.CommonConstant;
import com.swift.authority.common.exception.BusinessException;
import com.swift.authority.core.payload.PayLoad;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.util.UUID;

/**
 * @description: jwt工具类
 * @className: JwtUtil
 * @author: Ldanniel
 * @version： 1.0
 * @date: 2022 年 02 月 20 日
 **/
@Component
public class JwtUtil {
    private static final Logger log = LoggerFactory.getLogger(JwtUtil.class);
    @Autowired
    private RedisUtil redisUtil;
    /**
     * 生成个人私钥
     * @param userName 用户名
     * @return 私钥
     * @throws BusinessException
     */
    public  String createKeySecurity(String userName) throws BusinessException {
        String keySecurity = UUID.randomUUID().toString();
        boolean result = redisUtil.saveToCache(userName, keySecurity);
        //存放至数据库

        if(result){
            log.info("Generated The private key successfully ");
            return keySecurity;
        }
       throw new BusinessException("Generated The private key failure ");
    }
    /**
     * 根据用户的密文进行token对称加密（HMAC）
     *
     * @param payLoad payLoad
     * @param keySecurity 秘钥
     * @return token
     */
    public static String generateToken(PayLoad payLoad,String keySecurity) {
        log.info("Start to Generate token ...");
        //创建JWS头，设置签名算法和类型
        JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.HS256)
                .type(JOSEObjectType.JWT)
                .build();
        //将负载信息封装到Payload中
        Payload payload = new Payload(JSON.toJSONString(payLoad));
        //创建JWS对象
        JWSObject jwsObject = new JWSObject(jwsHeader, payload);
        try {
            //创建HMAC签名器
            JWSSigner jwsSigner = new MACSigner(keySecurity);
            //签名
            jwsObject.sign(jwsSigner);
            return jwsObject.serialize();
        } catch (JOSEException e) {
            log.error("Generate token exception", e);
            return null;
        }
    }

    /**
     * 可以 添加 私钥进行验证，暂时不用
     *
     * @param token token
     * @param keySecurity 秘钥
     * @return 校验结果
     * @throws JOSEException
     * @throws ParseException
     */
    public static boolean tokenVerify(String token,String keySecurity) throws JOSEException, ParseException {
        log.info("Start to check token ...");
        //从token中解析JWS对象
        JWSObject jwsObject = JWSObject.parse(token);
        PayLoad payLoad = JSON.parseObject(jwsObject.getPayload().toString(), PayLoad.class);

        //创建HMAC验证器
        JWSVerifier jwsVerifier = tokenValid(keySecurity);
        if (!jwsObject.verify(jwsVerifier)) {
            log.warn("The token signature is invalid ");
            throw new JOSEException("The token signature is invalid ");
        }

        //token过期判断
        boolean expireTime = (System.currentTimeMillis() - payLoad.getExp()) > CommonConstant.EXPIRE_TIME;
        if (expireTime) {
            log.warn("Token expired ");
            return true;
        }
        return false;
    }

    /**
     * 重新生成一个新的token
     *
     * @param token token
     * @param keySecurity 秘钥
     * @return 新的token
     */
    public static String refreshToken(String token,String keySecurity) {
        log.info("Start to refresh Token ...");
        PayLoad payLoad;
        try {
            //从token中解析JWS对象
            JWSObject jwsObject = JWSObject.parse(token);
            payLoad = JSON.parseObject(jwsObject.getPayload().toString(), PayLoad.class);

            return generateToken(payLoad,keySecurity);
        } catch (ParseException e) {
            log.error("JWT parse exception ", e);
            return null;
        }
    }

    public static PayLoad parseToken(String token,String keySecurity) throws Exception {
        //从token中解析JWS对象
        JWSObject jwsObject = JWSObject.parse(token);
        PayLoad payLoad = JSON.parseObject(jwsObject.getPayload().toString(), PayLoad.class);

        JWSVerifier jwsVerifier = tokenValid(keySecurity);
        if (!jwsObject.verify(jwsVerifier)) {
            log.warn("Token signature is invalid ");
            throw new BusinessException("Token signature is invalid ");
        }

        log.info("payLoad 解析结果为：{}", payLoad);
        return payLoad;
    }

    /**
     * 根据token获取用户名
     *
     * @param token token
     * @return 用户名
     * @throws Exception
     */
    public static String getUserName(String token,String keySecurity) throws Exception {
        //从token中解析JWS对象
        JWSObject jwsObject = JWSObject.parse(token);
        PayLoad payLoad = JSON.parseObject(jwsObject.getPayload().toString(), PayLoad.class);

        JWSVerifier jwsVerifier = tokenValid(keySecurity);
        if (!jwsObject.verify(jwsVerifier)) {
            log.warn("Token signature is invalid ");
            throw new BusinessException("Token signature is invalid ");
        }

        log.info("payLoad 解析结果为：{}", payLoad);
        return payLoad.getUser_name();
    }

    private static JWSVerifier tokenValid(String keySecurity) throws JOSEException {
        //创建HMAC验证器
        return new MACVerifier(keySecurity);
    }
}
